home *** CD-ROM | disk | FTP | other *** search
/ PD Collection CD 1 / PD Collection CD 1.iso / textual / pdftops / xpdf / c++ / Lexer < prev    next >
Text File  |  1996-06-08  |  7KB  |  340 lines

  1. //========================================================================
  2. //
  3. // Lexer.cc
  4. //
  5. // Copyright 1996 Derek B. Noonburg
  6. //
  7. //========================================================================
  8.  
  9. #ifdef __GNUC__
  10. //#pragma implementation
  11. #endif
  12.  
  13. #include <stdlib.h>
  14. #include <stddef.h>
  15. #include <string.h>
  16. #include <ctype.h>
  17. #include "Lexer.h"
  18. #include "Error.h"
  19.  
  20. //------------------------------------------------------------------------
  21. // Lexer
  22. //------------------------------------------------------------------------
  23.  
  24. Lexer::Lexer(Stream *str1, GBool freeStream1) {
  25.   str = str1;
  26.   buf = EOF;
  27.   cr = lf = gFalse;
  28.   freeStream = freeStream1;
  29.   str->reset();
  30. }
  31.  
  32. Lexer::~Lexer() {
  33.   if (freeStream)
  34.     delete str;
  35. }
  36.  
  37. Object *Lexer::getObj(Object *obj) {
  38.   char token[maxTokenLen+1];
  39.   char *p;
  40.   int n;
  41.   GBool comment;
  42.   GBool real;
  43.   int x;
  44.   GBool next;
  45.  
  46.   // skip whitespace and comments
  47.   if (buf == EOF)
  48.     buf = getChar();
  49.   comment = gFalse;
  50.   while (1) {
  51.     if (!isspace(buf)) {
  52.       if (!comment)
  53.     break;
  54.       if (buf == '%')
  55.     comment = gTrue;
  56.       else if (buf == '\n')
  57.     comment = gFalse;
  58.       else if (buf == EOF)
  59.     break;
  60.     }
  61.     buf = getChar();
  62.   }
  63.  
  64.   // check for end of stream
  65.   if (buf == EOF)
  66.     return obj->initEOF();
  67.  
  68.   // start reading token
  69.   p = token;
  70.   n = 0;
  71.  
  72.   // number
  73.   if ((buf >= '0' && buf <= '9') || buf == '-' || buf == '.') {
  74.     real = gFalse;
  75.     do {
  76.       if (n < maxTokenLen)
  77.     *p++ = buf;
  78.       ++n;
  79.       if (buf == '.')
  80.     real = gTrue;
  81.       buf = getChar();
  82.     } while ((buf >= '0' && buf <= '9') || (!real && buf == '.'));
  83.     *p = '\0';
  84.     if (real)
  85.       obj->initReal(atof(token));
  86.     else
  87.       obj->initInt(atoi(token));
  88.  
  89.   // string
  90.   } else if (buf == '(') {
  91.     buf = getChar();
  92.     while (buf != ')' && buf != EOF) {
  93.       next = gTrue;
  94.       if (buf == '\\') {
  95.     buf = getChar();
  96.     switch (buf) {
  97.     case 'n':
  98.       if (n < maxTokenLen)
  99.         *p++ = '\n';
  100.       ++n;
  101.       break;
  102.     case 'r':
  103.       if (n < maxTokenLen)
  104.         *p++ = '\r';
  105.       ++n;
  106.       break;
  107.     case 't':
  108.       if (n < maxTokenLen)
  109.         *p++ = '\t';
  110.       ++n;
  111.       break;
  112.     case 'b':
  113.       if (n < maxTokenLen)
  114.         *p++ = '\b';
  115.       ++n;
  116.       break;
  117.     case 'f':
  118.       if (n < maxTokenLen)
  119.         *p++ = '\f';
  120.       ++n;
  121.       break;
  122.     case '\\':
  123.       if (n < maxTokenLen)
  124.         *p++ = '\\';
  125.       ++n;
  126.       break;
  127.     case '(':
  128.       if (n < maxTokenLen)
  129.         *p++ = '(';
  130.       ++n;
  131.           break;
  132.     case ')':
  133.       if (n < maxTokenLen)
  134.         *p++ = ')';
  135.       ++n;
  136.       break;
  137.     case '0':
  138.     case '1':
  139.     case '2':
  140.     case '3':
  141.     case '4':
  142.     case '5':
  143.     case '6':
  144.     case '7':
  145.       x = buf - '0';
  146.       buf = getChar();
  147.       if (buf >= '0' && buf <= '7') {
  148.         x = (x << 3) + (buf - '0');
  149.         buf = getChar();
  150.         if (buf >= '0' && buf <= '7')
  151.           x = (x << 3) + (buf - '0');
  152.         else
  153.           next = gFalse;
  154.       } else
  155.         next = gFalse;
  156.       if (n < maxTokenLen)
  157.         *p++ = (char)x;
  158.       ++n;
  159.       break;
  160.     case '\n':
  161.       break;
  162.     default:
  163.       if (n < maxTokenLen)
  164.         *p++ = buf;
  165.       ++n;
  166.       break;
  167.     }
  168.       } else {
  169.     if (n < maxTokenLen)
  170.       *p++ = buf;
  171.     ++n;
  172.       }
  173.       if (next)
  174.     buf = getChar();
  175.     }
  176.     *p = '\0';
  177.     if (buf == EOF)
  178.       error(getPos(), "End of file inside string");
  179.     else
  180.       buf = EOF;  // kill the closing paren
  181.     obj->initString(token, p - token);
  182.  
  183.   // name
  184.   } else if (buf == '/') {
  185.     buf = getChar();
  186.     while (!isspace(buf) && buf!= '/' && buf != '%' && buf != '(' &&
  187.        buf != ')' && buf != '<' && buf != '>' && buf != '[' &&
  188.        buf != ']' && buf != '{' && buf != '}' && buf != EOF) {
  189.       if (n < maxTokenLen)
  190.     *p++ = buf;
  191.       ++n;
  192.       buf = getChar();
  193.     }
  194.     *p = '\0';
  195.     obj->initName(token);
  196.  
  197.   // array punctuation
  198.   } else if (buf == '[' || buf == ']') {
  199.     token[0] = buf;
  200.     token[1] = '\0';
  201.     buf = EOF;
  202.     obj->initCmd(token);
  203.  
  204.   // hex string or dict punctuation
  205.   } else if (buf == '<') {
  206.     buf = getChar();
  207.  
  208.     // dict punctuation
  209.     if (buf == '<') {
  210.       token[0] = token[1] = '<';
  211.       token[2] = '\0';
  212.       buf = EOF;
  213.       obj->initCmd(token);
  214.  
  215.     // hex string
  216.     } else {
  217.       while (1) {
  218.     while (isspace(buf))
  219.       buf = getChar();
  220.     if (buf == '>') {
  221.       buf = EOF;
  222.       break;
  223.     }
  224.     if (buf == EOF) {
  225.       error(getPos(), "End of file inside hex string");
  226.       break;
  227.     }
  228.     if (buf >= '0' && buf <= '9') {
  229.       x = (buf - '0') << 4;
  230.     } else if (buf >= 'A' && buf <= 'F') {
  231.       x = (buf - 'A' + 10) << 4;
  232.     } else if (buf >= 'a' && buf <= 'f') {
  233.       x = (buf - 'a' + 10) << 4;
  234.     } else {
  235.       error(getPos(), "Illegal character <%02x> in hex string", buf);
  236.       x = 0;
  237.     }
  238.     do {
  239.       buf = getChar();
  240.     } while (isspace(buf));
  241.     if (buf == EOF) {
  242.       error(getPos(), "End of file inside hex string");
  243.       break;
  244.     }
  245.     if (buf >= '0' && buf <= '9') {
  246.       x += buf - '0';
  247.     } else if (buf >= 'A' && buf <= 'F') {
  248.       x += buf - 'A' + 10;
  249.     } else if (buf >= 'a' && buf <= 'f') {
  250.       x += buf - 'a' + 10;
  251.     } else if (buf != '>') {
  252.       error(getPos(), "Illegal character <%02x> in hex string", buf);
  253.     }
  254.     if (n < maxTokenLen)
  255.       *p++ = (char)x;
  256.     ++n;
  257.     if (buf == '>') {
  258.       buf = EOF;
  259.       break;
  260.     }
  261.     buf = getChar();
  262.       }
  263.       *p = '\0';
  264.       obj->initString(token, p - token);
  265.     }
  266.  
  267.   // dict punctuation
  268.   } else if (buf == '>') {
  269.     buf = getChar();
  270.     if (buf == '>') {
  271.       token[0] = token[1] = '>';
  272.       token[2] = '\0';
  273.       buf = EOF;
  274.       obj->initCmd(token);
  275.     } else {
  276.       error(getPos(), "Illegal character '>'");
  277.       obj->initError();
  278.     }
  279.  
  280.   // command
  281.   } else if (buf != ')' && buf != '{' && buf != '}') {
  282.     do {
  283.       if (n < maxTokenLen)
  284.     *p++ = buf;
  285.       ++n;
  286.       buf = getChar();
  287.     } while (!isspace(buf) && buf != '%' && buf != '(' && buf != ')' &&
  288.          buf != '<' && buf != '>' && buf != '[' && buf != ']' &&
  289.          buf != '{' && buf != '}' && buf != EOF);
  290.     *p = '\0';
  291.     if (!strcmp(token, "true"))
  292.       obj->initBool(gTrue);
  293.     else if (!strcmp(token, "false"))
  294.       obj->initBool(gFalse);
  295.     else if (!strcmp(token, "null"))
  296.       obj->initNull();
  297.     else
  298.       obj->initCmd(token);
  299.  
  300.   // error
  301.   } else {
  302.     error(getPos(), "Illegal character '%c'", buf);
  303.     buf = EOF;  // eat the character to avoid an infinite loop
  304.     obj->initError();
  305.   }
  306.  
  307.   return obj;
  308. }
  309.  
  310. void Lexer::skipToNextLine() {
  311.   if (buf == EOF)
  312.     buf = getChar();
  313.   while (buf != '\n' && buf != EOF)
  314.     buf = getChar();
  315.   getChar();  // skip over end-of-line chars
  316.   buf = EOF;
  317. }
  318.  
  319. int Lexer::getChar() {
  320.   int c;
  321.  
  322.  start:
  323.   c = str->getChar();
  324.   if (c != '\n' && c != '\r') {
  325.     lf = cr = gFalse;
  326.   } else {
  327.     if (c == '\n') {
  328.       lf = gTrue;
  329.     } else {
  330.       cr = gTrue;
  331.       c = '\n';
  332.     }
  333.     if (lf && cr) {
  334.       lf = cr = gFalse;
  335.       goto start;
  336.     }
  337.   }
  338.   return c;
  339. }
  340.